home *** CD-ROM | disk | FTP | other *** search
/ SPACE 2 / SPACE - Library 2 - Volume 1.iso / apps / 42 / wind3.prf < prev    next >
Text File  |  1986-07-17  |  17KB  |  332 lines

  1. .!****************************************************************************
  2. .! 
  3. .! ANTIC PUBLISHING INC., COPYRIGHT 1985.  REPRINTED BY PERMISSION.
  4. .!
  5. .! ** Professional GEM ** by Tim Oren
  6. .!
  7. .! Proff File by ST enthusiasts at
  8. .! Case Western Reserve University
  9. .! Cleveland, Ohio
  10. .! uucp : decvax!cwruecmp!bammi
  11. .! csnet: bammi@case
  12. .! arpa : bammi%case@csnet-relay
  13. .! compuserve: 71515,155
  14. .!
  15. .!****************************************************************************
  16. .!
  17. .!
  18. .!****************************************************************************
  19. .!
  20. .!            Begin Part 3
  21. .!
  22. .!****************************************************************************
  23. .!
  24. .PART III THE DIALOG HANDLER
  25. .SH A MEANINGFUL DIALOG
  26. This issue of ST PRO GEM begins an exploration of ST GEM's dialog handler.  I
  27. will discuss basic system calls for presenting the dialog, and then continue
  28. with techniques for initializing and reading on/off button and "radio" button
  29. objects.  We  will also take some short side-trips into the operation
  30. of the GEM Resource Construction Set to assist you in building these dialogs.
  31. .PP
  32. There are a number of short C routines which accompany this column. These are
  33. stored as file GEMCL3.XMO in DL 5 on SIG*ATARI. Before reading this column, you
  34. should visit SIG*ATARI (go pcs-132) and download this file.
  35. .PP
  36. .SH DEFINING TERMS
  37. A dialog box is an "interactive form" in which the user may enter text and
  38. indicate selections by pointing with the mouse. Dialogs in GEM are
  39. "modal", that is, when a dialog is activated other screen functions
  40. such as menus and  window controls are suspended until the dialog is completed.
  41. .PP
  42. In most cases, the visual structure of a GEM dialog is specified within your
  43. application's resource file.  The GEM Resource Construction Set (RCS)
  44. is used to build a picture of the dialog.
  45. .PP
  46. When the RCS writes out a resource, it converts that picture into a tree of
  47. GEM drawing objects and stores this data structure within the resource.  Before
  48. your application can  display the dialog, it must load this resource file and
  49. find the  address of the tree which defines the dialog.
  50. .PP
  51. To load a resource, the AES checks its size and allocates memory for the
  52. load.  It then reads in the resource, adjusting internal pointers to
  53. reflect the load address.  Finally, the object sizes stored in the
  54. resource are converted from characters to pixels using the system font size.
  55. .PP
  56. A note for those with Macintosh experience:  Although Mac and GEM resources
  57. share a name, there are fundamental differences which can be misleading.  A Mac
  58. resource is a fork within a file; a GEM resource is a TOS file by itself.  Mac
  59. resources may be paged in and out of memory; GEM resources are monolithic.  GEM
  60. resources are internally tree structured; Mac resources are not.  Finally, Mac
  61. resources include font information, while ST GEM does this with font loading at
  62. the VDI level.
  63. .PP
  64. The resource load is done with the GEM AES call:
  65. .FB rsrc_load()
  66. ok = rsrc_load(ADDR("MYAPP.RSC"));
  67. .FE
  68. "MYAPP" should be replaced with the name of your program. Resources
  69. conventionally have the same primary name as their application, with the RSC
  70. extent name instead of PRG.  The ok flag returned by rsrc_load will be FALSE is
  71. anything went wrong during the load.
  72. .PP
  73. The most common causes of failure are the resource not being in the
  74. application's subdirectory, or lack of sufficient memory for GEM to allocate
  75. space for the resource.  If this happens, you must terminate the program
  76. immediately.
  77. .PP
  78. Once you have loaded the resource, you find the address of a dialog's object
  79. tree with:
  80. .FB rsrc_gaddr()
  81. rsrc_gaddr(R_TREE, MYDIALOG, &tree);
  82. .FE
  83. Tree is a 32-bit variable which will receive the address of the root
  84. node of the tree.
  85. .PP
  86. The mnemonic MYDIALOG should be replaced with the name you gave your dialog
  87. when defining it in the RCS.  At the same time that it writes the resource, RCS
  88. generates a corresponding .H file containing tree and object names.
  89. In order to use these mnemonics within your program, you must include
  90. the name file in your compile:  #include "MYAPP.H"
  91. .SH BUG ALERT!
  92. When using the DRI/Alcyon C compiler, .H files must be in the compiler's home
  93. directory or they will not be found.  This is especially annoying using a two
  94. floppy drive ST development system. The only way around this is to explicitly
  95. reference an alternate disk in the #include, for instance:  "B:MYAPP.H".
  96. [Ed. Note: Use the -i flag with the C pre-processor to name the include
  97. directories].
  98. .PP
  99. Now that the address of the dialog tree has been found, you are ready to
  100. display it.  The standard (and minimal) sequence for doing so is given in
  101. routine hndl_dial() in the download.  We will now walk through each
  102. step in this procedure.
  103. .PP
  104. The form_center call establishes the location of the dialog on the screen.
  105. Dialog trees generated by the RCS have an undefined origin (upper-left corner).
  106. .PP
  107. Form_center computes the upper-left location necessary to center the dialog
  108. on the screen, and inserts it into the OB_X and OB_Y fields of the ROOT object
  109. of the tree.  It also computes the screen rectangle which the dialog
  110. will occupy on screen and writes its pixel coordinates into variables
  111. xdial, ydial, wdial, and hdial.
  112. .PP
  113. There is one peculiarity of form_center which occasionally causes trouble.
  114. Normally the rectangle returned in xdial, etc., is exactly the same size as the
  115. basic dialog box.
  116. .PP
  117. However, when the OUTLINED enhancement has been specified for the box,
  118. form_center adds a three pixel margin to the rectangle returned. This
  119. causes the screen area under the outline to be correctly redrawn later
  120. (see below).  Note that OUTLINED is part of the standard dialog box in
  121. the RCS.  Other enhancements, such as SHADOWED or "outside" borders
  122. are NOT handled in this fashion, and you must compensate  for them in
  123. your code. 
  124. .PP
  125. The next part of the sequence is a form_dial call with a zero parameter.
  126. This reserves the screen for the dialog action about to occur. Note that the C
  127. binding given for form_dial in the DRI documents is in error: there are nine
  128. parameters, not five.  The first set of xywh arguments is actually used with
  129. form_dial calls 1 and 2 only, but place holders must be supplied in all cases.
  130. .PP
  131. The succeeding form_dial call (parameter one) animates a "zoom box" on the
  132. screen which moves and grows from the first screen rectangle given to
  133. the second rectangle, where the dialog will be displayed.
  134. .PP
  135. The use of this call is entirely optional.  In choosing whether to use it or
  136. not, you should consider whether the origin of the "zoom" is relevant to the
  137. operation.  For instance, a zoom from the menu bar is relatively meaningless,
  138. while a zoom from an object about to be edited in the dialog provides visual
  139. feedback to the user, showing whether the correct object was chosen.
  140. .PP
  141. If the origin is not relevant, then the zoom is just a time-waster. If  you
  142. decide to include these effects, consider a "preferences" option in  your app
  143. which will allow the experienced and jaded user to turn them off in the
  144. interests of speed.
  145. .PP
  146. The objc_draw call actually displays the dialog on the screen. Note that the
  147. address of the tree, the beginning drawing object, and the drawing depth are
  148. passed as arguments, as well as the rectangle allotted for the dialog.
  149. .PP
  150. In general, dialogs (and parts of dialogs) are  ALWAYS drawn beginning at the
  151. ROOT (object zero).  When you want to draw  only a portion of the
  152. dialog, adjust the clipping rectangle, but not the object number.
  153. This ensures that the background of the dialog is always  drawn correctly.
  154. .PP
  155. The objc_xywh() utility in the download can be used to find the clipping
  156. rectangle for any object within a dialog, though you may have to allow an extra
  157. margin is you have used shadows, outlines, or outside borders with the object.
  158. .PP
  159. Calling form_do transfers control to the AES, which animates the dialog for
  160. user interaction.  The address of the dialog tree is passed as a
  161. parameter.  The second paramter is the number of the editable object
  162. at which the text cursor will first be positioned. If you have no text
  163. fields, pass a zero.  Note that again the DRI documents are in error:
  164. passing a -1 default may crash the system. Also be careful that the
  165. default which you specify is actually a text field; no error checking
  166. is performed. 
  167. .PP
  168. The form_do call returns the number of the object on which the clicked to
  169. terminate the dialog.  Usually this is a button type object with the EXIT and
  170. SELECTABLE attributes set.  Setting the DEFAULT attribute as well will cause an
  171. exit on that object is a carriage return is struck while in the dialog.
  172. .PP
  173. If the top bit of the return is set, it indicates that  the exit object had
  174. the TOUCHEXIT attribute and was selected with a double-click.  Since very few
  175. dialogs use this combination, the sample code simply masks off the top bit.
  176. .PP
  177. The next form_dial call reverses the "zoom box", moving it from the dialog's
  178. location back to the given x,y,w,h.  The same cautions apply here as above.
  179. .PP
  180. The final form_dial call tells GEM that the dialog is complete, and that the
  181. screen area occupied by the dialog is now considered "dirty" and needs to be
  182. redrawn.  Using the methods described in our last column, GEM then
  183. sends redraws to all windows which were overlaid, and does any
  184. necessary redrawing of the menu or desktop itself.
  185. .PP
  186. There is one notable "feature" of form_dial(3):  It always redraws an area
  187. which is two pixels wider and higher than your request!  This was probably
  188. included to make sure that drop-shadows were cleaned up, and is usually
  189. innocuous.
  190. .SH A HANDY TRICK
  191. Use of the form_dial(3) call is not limited to dialogs.  You can use
  192. it to force the system to redraw any part of the screen.  The
  193. advantage of this method is that the redraw area need not lie entirely
  194. within a window, as was necessary with the send_redraw method detailed
  195. in the last column.  A disadvantage is that this method is  somewhat
  196. slower, since the AES has to decide who gets the redraws.
  197. .SH CLEAN UP
  198. As a last step, you need to clear the SELECTED flag in the object which was
  199. clicked.  If you do not do this, the object will  be drawn inverted the next
  200. time you call the dialog.  You could clear the flag with the GEM objc_change
  201. call, but it is inefficient since you do not need to redraw the object.
  202. .PP
  203. Instead, use the desel_obj() code in the  download, which modifies the
  204. object's OB_STATE field directly.  Assuming  that ret_obj contains the exit
  205. object returned by hndl_dial, the call:
  206. .FB desel_obj()
  207. desel_obj(tree, ret_obj);
  208. .FE
  209. will do the trick.
  210. .SH RECAP
  211. The basic dialog handling method I have described contains three steps:
  212. initialization (rsrc_gaddr), dialog presentation (hndl_dial), and cleanup
  213. (desel_obj).
  214. .PP
  215. As we build more advanced dialogs, these same basic steps will be performed,
  216. but they will grow more complex. The initialization will include setting up
  217. proper object text and states, and the cleanup phase will also interrogate the
  218. final states of objects to find out what the user did.
  219. .SH BUTTON, BUTTON
  220. The simple dialogs described above contain only exit buttons as active objects.
  221. As such, they are little more than glorified alert boxes.
  222. .PP
  223. We will now increase the complexity a little by considering non-exit buttons.
  224. These are constructed by setting the SELECTABLE attribute on a button object.
  225. At run-time, such an object will toggle its state between selected
  226. (highlighted) and non-selected  whenever the user clicks on it.  (You
  227. can set the SELECTABLE attribute  of other types of objects and use
  228. them instead of actual buttons, but  be sure that the user will be
  229. able to figure out what you intend!) 
  230. .PP
  231. Having non-exit buttons forces us to consider the problem of initializing
  232. them before the dialog, and interrogating and resetting them afterward.
  233. .PP
  234. Since a button is a toggle, it is usually associated with a flag variable in
  235. the program.  As part of the initialization, you should test the flag variable,
  236. and if true call:
  237. .FB sel_obj()
  238. sel_obj(tree, BTNOBJ);
  239. .FE
  240. which will cause the button to appear highlighted when the dialog is first
  241. drawn.  Sel_obj() is in the download.  BTNOBJ is replaced with the  name you
  242. gave your button when you defined it in the RCS.  Since the button starts out
  243. deselected, you don't have to do anything if your flag variable is false.
  244. .PP
  245. After the dialog has completed, you need to check the object's state. The
  246. selectp() utility does so by masking the OB_STATE field.  You can simply assign
  247. the result of this test to your flag variable, but be sure that the dialog was
  248. exited with an OK button, not with a CANCEL! Again, remember to clean up the
  249. button with desel_obj(). (It's often easiest to deselect all buttons
  250. just before you leave the dialog routine, regardless of the final
  251. dialog state.) 
  252. .SH WHO'S GOT THE BUTTON?
  253. Another common use of buttons in a  dialog is to select one of a set
  254. of possible options.  In GEM, such objects are called radio buttons.
  255. This term recalls automobile radio tuners where pushing in one button
  256. pops out any others.  In like fashion, selecting any one of a set of
  257. radio buttons automatically deselects all of the others.
  258. .PP
  259. To use the radio button feature, you must do some careful work with the
  260. Resource Construction Set.
  261. .PP
  262. First, each member of a set of  radio buttons must be children of the same
  263. parent object within the  object tree. To create this structure, put a hollow
  264. box type object in the  dialog, make it big enough to hold all of the buttons,
  265. and then put the buttons into the box one at a time.
  266. .PP
  267. By nesting the buttons within the  box object, you force them to be its
  268. children.  Each of the buttons must have both the SELECTABLE and RADIO BUTTON
  269. attributes set.  When you are done, you may make the containing box
  270. invisible by setting its border to zero, but do not FLATTEN it!
  271. .PP
  272. Since each radio button represents a different option, you must usually
  273. assign a name to each object.  When initializing the dialog, you must check
  274. which option is currently set, and turn on the corresponding button only.  A
  275. chain of if-then-else structures assures that only one button will be selected.
  276. .PP
  277. At the conclusion of the dialog, you must check each button with selectp()
  278. and make the appropriate adjustments to internal variables. Again, an
  279. if-then-else chain is appropriate since only one button may be
  280. selected.  Either deselect the chosen button within this chain or do
  281. them all at the end. 
  282. .PP
  283. There is one common use of radio buttons in which you may short-cut this
  284. procedure.  If the buttons each represent one possible value of a numeric
  285. variable, for instance, a set of selector buttons representing  colors
  286. from zero to seven, then you can compute the initial object directly.
  287. .PP
  288. In order for this technique to work, you must use a special capability of the
  289. RCS.  Insert the object corresponding to a zero value at the top (or left) of
  290. your array of buttons, then put the "one" button below (or right) of it, and so
  291. on.
  292. .PP
  293. When the buttons are complete,  the SORT operation is used to guarantee that
  294. the top/left object is in fact the first child of the parent box with
  295. the others following in order.  Due to the details of object tree
  296. structure (to be discussed in the next column), this will guarantee
  297. that these objects are contiguous in the resource.
  298. .PP
  299. If you assign a name (say BUTTON1) to the first button,  then you can
  300. initialize the correct button with the call:
  301. .FB sel_obj()
  302. sel_obj(tree, BUTTON1 + field);
  303. .FE
  304. where field is the variable of interest.
  305. .PP
  306. When the dialog is complete, you can scan the radio buttons to compute the
  307. new value for the underlying variable.  The encode() procedure in the download
  308. will do this.  As always, remember to deselect the buttons at the end.
  309. .PP
  310. You can use offsets or multipliers if your variable's values don't start with
  311. zero or increment by one.  If the values are irregular you may be able to use a
  312. lookup table, at the cost of additional code.
  313. .SH COMING UP NEXT
  314. In the next column, I will discuss the internal structure of object
  315. trees.  Then we'll use that knowledge to build a piece of code which
  316. will "walk" an entire tree and apply a function to each object. We'll
  317. apply this code to do all of the button deselects  with a single call!
  318. I'll also look at handling editable text fields and discuss some ways
  319. to alter a dialog's appearance at run-time. 
  320. .SH DISPELL GREMLINS
  321. An editing error caused an omission in the first installment of ST PRO
  322. GEM.  The window components RTARROW and DNARROW should have been
  323. listed along with HSLIDE as the horizontal equivalents of the vertical
  324. slider components which were discussed.
  325. .!
  326. .!
  327. .!*****************************************************************************
  328. .!*                                          *
  329. .!*                End Part 3                      *
  330. .!*                                          *
  331. .!*****************************************************************************
  332.